package top.lyjwn.todo.common.utils;

import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Tree<ID, MODEL extends Tree.Node> {

    public static Tree instance() {
        return new Tree();
    }

    public List<MODEL> generate(List<? extends Node<ID, MODEL>> list) {
        Map<ID, Node<ID, MODEL>> map = new HashMap<>();
        List<MODEL> treelist = new ArrayList<>();

        if (null == list || list.isEmpty()) {
            return null;
        }
        map = list.stream().collect(Collectors.toMap(Node<ID, MODEL>::getId, a -> a, (k1, k2) -> k1));
        //for (int i = 0; i < list.size(); i++) {
        //   map.put(list.get(i).getId(), list.get(i));
        //}
        // 将list集合对象转换为json的字符串
        // 如果id是父级的话就放入tree中treelist
        for (Node<ID, MODEL> node : list) {
            if (null == map.get(node.getPid())) {
                treelist.add(node.get());
            } else {
                // 子级通过父id获取到父级的类型
                Node parent = map.get(node.getPid());
                // 父级获得子级，再将子级放到对应的父级中
                parent.getChildren().add(node.get());
                parent.setLeaf(false);
            }
        }
        return treelist;
    }

    /**
     * 将树转换为节点列表
     *
     * @param tree
     * @return
     */
    public List<MODEL> toNodes(List<MODEL> tree) {
        List<MODEL> nodes = new ArrayList<>();
        for (MODEL node : tree) {
            if (!CollectionUtils.isEmpty(node.getChildren())) {
                List<MODEL> _nodes = toNodes(node.getChildren());
                nodes.addAll(_nodes);
            }
            nodes.add(node);
        }
        return nodes;
    }

    public static abstract class Node<ID, MODEL> {


        public abstract ID getId();

        public abstract ID getPid();

        private boolean leaf = true;

        public boolean isLeaf() {
            return leaf;
        }

        public void setLeaf(boolean leaf) {
            this.leaf = leaf;
        }

        public MODEL get() {
            return (MODEL) this;
        }

        public List<MODEL> children = new ArrayList<>();

        public List<MODEL> getChildren() {
            return children;
        }

        public void setChildren(List<MODEL> children) {
            this.children = children;
        }
    }
}
